package edu.chalmers.AV_2DPlatformerFramework.Utility;

import edu.chalmers.AV_2DPlatformerFramework.Utility.VectorUtility;
import java.awt.geom.Point2D;

/**
 * Wrapper class for {@code Point2D.Double} to represent Euclidean vectorial
 * quantities.
 * @version 1.2
 * @author Joakim Karlsson, Gustav Vidhög
 * @revised Richard Sundqvist, 2014-05-09: Implemented copy method.
 * @revised Gustav Vidhög, 20140514
 */
public class Vector2D extends Point2D.Double {
    
    /**
     * Constructs and initializes a {@code Vector2D} with coordinates (0, 0).
     * @author Joakim Karlsson, Gustav Vidhög
     * @version 1.0
     * @since 1.0
     */
    public Vector2D() {
        super();
    }
    
    /**
     * Constructs and initializes a {@code Vector2D} with the specified
     * coordinates.
     * @param x - the X coordinate of the newly constructed {@code Vector2D}
     * @param y - the Y coordinate of the newly constructed {@code Vector2D}
     * @author Joakim Karlsson, Gustav Vidhög
     * @version 1.0
     * @since 1.0
     */
    public Vector2D(double x, double y) {
        super(x,y);
    }

/**
     * Creates and returns a deep copy of this {@code Vector2D}. For any
     * {@code Vector2D} {@code v}, the expression:
     * <blockquote>
     * <pre>
     * v.copy() != v</pre></blockquote>
     * and the expression:
     * <blockquote>
     * <pre>
     * x.copy().equals(x)</pre></blockquote>
     * are both {@code true}.
     * @return a deep copy of this {@code Vector2D}.
     * @author Richard Sundqvist
     * @version 1.0
     * @since 1.1
     */
    public Vector2D copy() {
        return new Vector2D(this.x, this.y);
    }
    
    /**
     * Indicates whether some other object is "equal to" this {@code Vector2D}.
     * @param obj - the reference {@code Object} with which to compare.
     * @return {@code true} if this {@code Vector2D} is the same as the
     * {@code obj} argument; {@code false} otherwise.
     * @author Gustav Vidhög
     * @version 1.0
     * @since 1.2
     */
    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        } else if (obj == null || obj.getClass() != this.getClass()) {
            return false;
        } else {
            Vector2D vector = (Vector2D) obj;
            return (this.x == vector.x && this.y == vector.y);
        }
    }
    
    /**
     * Returns a hash code value for the {@code Vector2D}.
     * @return a hash code value for this {@code Vector2D}.
     * @author Gustav Vidhög
     * @version 1.0
     * @since 1.2
     */
    @Override
    public int hashCode() {
        long tempX = java.lang.Double.doubleToLongBits(x);
        long tempY = java.lang.Double.doubleToLongBits(y);
        return (((int) (tempX ^ (tempX >>> 32))) * 131 +
                ((int) (tempY ^ (tempY >>> 32))) * 137);
    }
    
    /**
     * Tests whether the norm of the difference between this {@code Vector2D}
     * and another is less than a certain value. Intended to provide an informal
     * "almost equal" -measure for cases where approximate equality is
     * sufficient and potential errors caused by floating-point arithmetic would
     * make comparison for exact equality unsuitable.
     * @param vector - {@code Vector2D} to compare with.
     * @param epsilon - maximum difference between this {@code Vector2D} and
     * {@code vector}.
     * @return {@code true} if the norm of the difference between this
     * {@code Vector2D} and {@code vector} is less than {@code epsilon};
     * {@code false} otherwise. Always returns {@code false} for nonpositive
     * {@code epsilon}.
     */
    public boolean isWithinDistance(Vector2D vector, double epsilon) {
        return (VectorUtility.norm(VectorUtility.subtract(vector, this)) <
                epsilon);
    }
}
